import pandas as pd
import numpy as np

# 设置中文显示
import matplotlib.pyplot as plt
import seaborn as sns
import mplfinance as mpf
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

# 读取Excel文件
def analyze_byd_stock_data(file_path="比亚迪后复权历史行情数据.xlsx"):
    try:
        # 读取Excel文件
        df = pd.read_excel(file_path)
        
        # 1. 观察数据形状
        print("数据形状:")
        print(f"行数: {df.shape[0]}")
        print(f"列数: {df.shape[1]}")
        
        # 2. 输出数据前5行
        print("\n数据前5行:")
        print(df.head())
        
        # 3. 显示数据类型
        print("\n数据类型:")
        print(df.dtypes)
        
        # 4. 对定量变量进行描述性分析
        print("\n定量变量的描述性分析:")
        # 自动识别数值型列
        numeric_cols = df.select_dtypes(include=[np.number]).columns
        
        if len(numeric_cols) > 0:
            # 基本统计描述
            print("基本统计信息:")
            print(df[numeric_cols].describe())
            
            # 计算额外的统计指标
            print("\n额外统计指标:")
            stats_df = pd.DataFrame()
            
            for col in numeric_cols:
                stats = {
                    '列名': col,
                    '中位数': df[col].median(),
                    '四分位数Q1': df[col].quantile(0.25),
                    '四分位数Q3': df[col].quantile(0.75),
                    '极差': df[col].max() - df[col].min(),
                    '标准差': df[col].std(),
                    '偏度': df[col].skew(),
                    '峰度': df[col].kurtosis()
                }
                stats_df = pd.concat([stats_df, pd.DataFrame([stats])], ignore_index=True)
            
            print(stats_df)
        else:
            print("未发现数值型变量")
            
        # 5. 计算变量之间的相关系数
        print("\n变量间相关系数矩阵:")
        corr_matrix = df[numeric_cols].corr()
        print(corr_matrix)
        
        # 6. 绘制相关系数热力图
        print("\n正在绘制相关系数热力图...")
        plt.figure(figsize=(12, 10))
        # 创建热力图
        heatmap = sns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap="coolwarm", 
                             square=True, linewidths=.5, cbar_kws={"shrink": .8})
        plt.title("比亚迪股票数据变量相关系数热力图")
        plt.xticks(rotation=45, ha="right")
        plt.tight_layout()
        
        # 保存热力图
        plt.savefig("byd_correlation_heatmap.png", dpi=300)
        print("热力图已保存为 'byd_correlation_heatmap.png'")
        
        # 显示热力图
        plt.show()
        
        # 7. 绘制2023年全年收盘价时序图
        print("\n正在绘制2023年收盘价时序图...")
        
        # 确保日期列是datetime类型
        if '日期' in df.columns:
            df['日期'] = pd.to_datetime(df['日期'])
            
            # 筛选2023年的数据
            df_2023 = df[df['日期'].dt.year == 2023].copy()
            
            if not df_2023.empty:
                plt.figure(figsize=(14, 7))
                plt.plot(df_2023['日期'], df_2023['收盘'], marker='o', linestyle='-', color='blue', linewidth=2, markersize=4)
                
                # 添加均线（例如30日均线）
                if len(df_2023) >= 30:
                    df_2023['MA30'] = df_2023['收盘'].rolling(window=30).mean()
                    plt.plot(df_2023['日期'], df_2023['MA30'], linestyle='--', color='red', linewidth=2, label='30日均线')
                
                plt.title('比亚迪2023年收盘价走势图')
                plt.xlabel('日期')
                plt.ylabel('收盘价（元）')
                plt.grid(True, linestyle='--', alpha=0.7)
                plt.xticks(rotation=45)
                plt.tight_layout()
                
                if len(df_2023) >= 30:
                    plt.legend()
                
                # 保存时序图
                plt.savefig("byd_2023_close_price.png", dpi=300)
                print("2023年收盘价时序图已保存为 'byd_2023_close_price.png'")
                
                # 显示时序图
                plt.show()
            else:
                print("未找到2023年的数据")
        else:
            print("数据中未找到'日期'列")
        
        # 8. 绘制2023年4月到6月的K线图
        print("\n正在绘制2023年4月到6月的K线图...")
        
        # 确保日期列是datetime类型
        if '日期' in df.columns:
            df['日期'] = pd.to_datetime(df['日期'])
            
            # 设置日期列为索引
            df.set_index('日期', inplace=True)
            
            # 筛选2023年4月到6月的数据
            start_date = '2023-04-01'
            end_date = '2023-06-30'
            df_kline = df.loc[start_date:end_date].copy()
            
            if not df_kline.empty:
                # 确保必要的列存在
                if all(col in df_kline.columns for col in ['开盘', '最高', '最低', '收盘']):
                    # 创建K线图
                    plt.figure(figsize=(14, 8))
                    
                    # 设置K线图样式
                    mc = mpf.make_marketcolors(up='red', down='green', volume='inherit')
                    s = mpf.make_mpf_style(marketcolors=mc, gridstyle=':', y_on_right=False)
                    
                    # 将中文列名映射为英文列名
                    kline_data = df_kline.rename(columns={
                        '开盘': 'Open',
                        '最高': 'High',
                        '最低': 'Low',
                        '收盘': 'Close',
                        '成交量': 'Volume'
                    })
                    
                    # 绘制K线图
                    mpf.plot(kline_data, type='candle', style=s, volume=True, 
                             title='比亚迪2023年4月-6月K线图', 
                             ylabel='价格（元）', ylabel_lower='成交量', 
                             savefig='byd_2023_apr_jun_kline.png')
                    
                    print("2023年4月-6月K线图已保存为 'byd_2023_apr_jun_kline.png'")
                    
                    # K线图分析
                    print("\nK线图分析:")
                    # 统计这段时间内的涨跌情况
                    total_days = len(df_kline)
                    up_days = len(df_kline[df_kline['收盘'] > df_kline['开盘']])
                    down_days = len(df_kline[df_kline['收盘'] < df_kline['开盘']])
                    flat_days = total_days - up_days - down_days
                    
                    # 计算涨跌幅
                    start_price = df_kline['开盘'].iloc[0]
                    end_price = df_kline['收盘'].iloc[-1]
                    price_change = (end_price - start_price) / start_price * 100
                    
                    # 计算最高价和最低价
                    highest_price = df_kline['最高'].max()
                    lowest_price = df_kline['最低'].min()
                    
                    print(f"总交易日数: {total_days}")
                    print(f"上涨天数: {up_days} ({up_days/total_days*100:.1f}%)")
                    print(f"下跌天数: {down_days} ({down_days/total_days*100:.1f}%)")
                    print(f"平盘天数: {flat_days}")
                    print(f"期初价格: {start_price:.2f}元")
                    print(f"期末价格: {end_price:.2f}元")
                    print(f"期间涨跌幅: {price_change:.2f}%")
                    print(f"期间最高价: {highest_price:.2f}元")
                    print(f"期间最低价: {lowest_price:.2f}元")
                else:
                    print("数据中缺少绘制K线图所需的列（开盘、最高、最低、收盘）")
            else:
                print("未找到2023年4月到6月的数据")
        else:
            print("数据中未找到'日期'列")
            
    except Exception as e:
        print(f"分析过程中出现错误: {e}")

if __name__ == "__main__":
    analyze_byd_stock_data()